'''  
- bei erstem Kontakt mit Server bekommt der Client :math:`g,h,p`
- Client bestimmt:

    * :math:`k` und :math:`l` zufaellig
    * berechnet :math:`g^k \cdot h^l`
    
- wenn er einen distinguished point gefunden hat, sendet er :math:`y_i, k_i, l_i` an den Server
- wenn er Bestaetigung von Server ueber gefundene Kollision bekommt, stoppt der Client die Berechnungen

'''

import serverinfo
import socket
import json
from utility import PollardSeries, checkDistinguishPoint
import time

class PollardClient():
	'''
        Die Klasse ``DHClient`` stellt einen Client, der Daten mit einem Server austauscht, zur Verfuegung.
    '''
	
	def __init__(self):#
		'''
			init socket usw
		'''
		self.sock = None
		self.connected = False
		self.HOST = serverinfo.HOST
		self.PORT = serverinfo.PORT
		self.getConfirm = None
		
		# infor from server by the first contact
		self.g = None
		self.p = None
		self.h = None
		
		# Pollard Series
		self.pollard = None
		
	def setup(self):#
		'''
			Erzeugt eine Socket und oeffenet eine Verbindung zum Server.
		'''
		try:
			self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
			self.sock.connect((self.HOST, self.PORT))
			self.connected = True
		except socket.error as ex:
			print ex
			self.connected = False
		pass
	
	def sendFirstContact(self):#
		'''
			send ``{"FirstContact":true}`` an Server
		'''
		fc = r'{"FirstContact": true}'
		self.sock.send(fc)
		server_response = self.sock.recv(1024)
		# print "from server: %s" %server_response
		self.parseInput(server_response)
	
	def computeDistinguishPoint(self):#
		'''
		berechnet den naechsten distinguish Point
		'''
		(y,k,l) = self.pollard.computeNextElement()
		while not checkDistinguishPoint(y,k,l):
			(y,k,l) = self.pollard.computeNextElement()

		self.y = y
		self.k = k
		self.l = l
		pass
	
	def sendDistinguishPoint(self):#
		'''
			sendet ``{\"Point\": {\"y\": <>, \"k\": <>, \"l\": <>}}`` an dem Server.
		'''
		self.setup()
		point = '{"Point": {"y":\n\t %d, \n"k":\n\t %d, \n"l":\n\t %d}}'%(self.y,self.k, self.l)
		self.sock.send(point)
		# print "sent to server: >>%s<<" %point
		server_response = self.sock.recv(1024)
		# print "received from server: >>%s<<" %server_response
		self.parseInput(server_response)
		
	
	def parseInput(self,jsonString):#
		'''
		parsert den JSON-String vom Server
		'''
		try:
			jsonObj = json.loads(jsonString)
			value = jsonObj.get("DLProblem")
			if value is None:
				value = jsonObj.get("Confirm")
				if not (value is None):
					self.getConfirm = value
			else:
				self.h = value["h"]
				self.g = value["g"]
				self.p = value["p"]
				print "DH Problem: g = %d, h = %d, p = %d" %(self.g,self.h,self.p)
				self.pollard = PollardSeries(self.g, self.h, self.p)
		except ValueError:
			print "Unknown string: %s" %jsonString
	
	def stop(self):#
		'''
		schliest die Verbindung zum Server.
		'''
		self.sock.close()

if __name__ == "__main__":
	c = PollardClient()
	countTry = 10
	while countTry > 0:
		try:
			c.setup()
			if c.connected :
				c.sendFirstContact()
				while not c.getConfirm:
					c.computeDistinguishPoint()
					c.sendDistinguishPoint()
			else:
				print "Keine Verbindung zum Server"
				countTry -= 1
				print "count down: %d" %countTry
				time.sleep (10)				
		except socket.error as ex:
			print ex
			print "keine Verbindung zum Server."
			print "%s:%d" %(serverinfo.HOST,serverinfo.PORT)
			c.stop()
			countTry -= 1
			print "count down: %d" %countTry
			time.sleep (10)				
